package com.egg.auth.service.login;

import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.context.model.SaStorage;
import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import com.egg.auth.entity.user.User;
import com.egg.auth.enums.account.AccountTypeEnum;
import com.egg.auth.enums.account.DeviceTypeEnum;
import com.egg.auth.model.LoginUserInfo;
import com.egg.auth.service.dept.IDeptService;
import com.egg.auth.service.role.IRoleService;
import com.egg.auth.service.user.IUserService;
import com.egg.common.core.constant.CoreConstant;
import com.egg.common.util.IpUtil;
import com.egg.common.util.JsonUtil;

import java.util.Optional;

/**
 * 登录鉴权助手
 * <p>
 * account_type 为 账号类型 同一个用户表 可以有多种用户类型 例如 password,wechat
 * device 为 设备类型 同一个用户类型 可以有 多种设备类型 例如 web,ios
 * 可以组成 用户类型与设备类型多对多的 权限灵活控制
 * <p>
 * 多用户体系 针对 多种用户类型 但权限控制不一致
 * 可以组成 多用户类型表与多设备类型 分别控制权限
 */
public class LoginHelper {


    private static IUserService userService;

    public void setUserServiceBean(IUserService initService) {
        userService = initService;
    }

    private static IRoleService roleService;

    public void setRoleServiceBean(IRoleService initService) {
        roleService = initService;
    }

    private static IDeptService deptService;

    public void setDeptServiceBean(IDeptService initService) {
        deptService = initService;
    }


    public static final String LOGIN_USER_KEY = "loginUser";
    public static final String TENANT_ID_KEY = "tenantId";
    public static final String USER_ID_KEY = "userId";


    public static LoginUserInfo buildLoginUser(AccountTypeEnum loginType, Long userId) {
        User user = userService.baseGetById(userId);
        return buildLoginUser(loginType, user);
    }

    public static LoginUserInfo buildLoginUser(AccountTypeEnum accountType, User user) {
        LoginUserInfo loginUserInfo = new LoginUserInfo();
        loginUserInfo.setTenantId(CoreConstant.DEFAULT_ID.toString());
        loginUserInfo.setUserId(user.getId());
        loginUserInfo.setNickname(user.getNickname());
        loginUserInfo.setAvatar(user.getAvatar());
        loginUserInfo.setDeptList(JsonUtil.listToList(deptService.findEnabledByUserId(user.getId()), LoginUserInfo.Dept.class));
        loginUserInfo.setRoleList(JsonUtil.listToList(roleService.findEnabledByUserId(user.getId()), LoginUserInfo.Role.class));
        loginUserInfo.setFuncPerms(roleService.findFuncPermByUserId(user.getId()));
        loginUserInfo.setDataPerms(roleService.findDataPermByUserId(user.getId()));
        loginUserInfo.setAccountType(accountType.getCode());
        loginUserInfo.setIp(IpUtil.requestIp());
        return loginUserInfo;
    }

    /**
     * 登录
     *
     * @param loginUserInfo 登录用户
     * @param deviceType    设备类型
     */
    public static void login(LoginUserInfo loginUserInfo, DeviceTypeEnum deviceType) {
        login(loginUserInfo, deviceType, Optional.empty());
    }

    /**
     * 登录
     *
     * @param loginUserInfo 登录用户
     * @param deviceType    设备类型
     * @param modelOpt      扩展信息
     */
    public static void login(LoginUserInfo loginUserInfo, DeviceTypeEnum deviceType, Optional<SaLoginModel> modelOpt) {
        loginUserInfo.setDeviceType(deviceType.getCode());
        SaStorage storage = SaHolder.getStorage();
        storage.set(TENANT_ID_KEY, loginUserInfo.getTenantId());
        storage.set(USER_ID_KEY, loginUserInfo.getUserId());
        storage.set(LOGIN_USER_KEY, loginUserInfo);
        SaLoginModel model = new SaLoginModel();
        if (modelOpt.isPresent()) {
            model = modelOpt.get();
        }
        model.setDevice(deviceType.getCode());
        model.setExtra(TENANT_ID_KEY, loginUserInfo.getTenantId())
                .setExtra(USER_ID_KEY, loginUserInfo.getUserId());
        StpUtil.login(loginUserInfo.getLoginId(), model);
        StpUtil.getTokenSession().set(LOGIN_USER_KEY, loginUserInfo);
    }

    /**
     * 获取用户(多级缓存)
     */
    public static LoginUserInfo getLoginUser() {
        LoginUserInfo loginUserInfo = (LoginUserInfo) SaHolder.getStorage().get(LOGIN_USER_KEY);
        if (loginUserInfo != null) {
            return loginUserInfo;
        }
        SaSession session = StpUtil.getTokenSession();
        if (ObjectUtil.isNull(session)) {
            return new LoginUserInfo();
        }
        loginUserInfo = (LoginUserInfo) session.get(LOGIN_USER_KEY);
        SaHolder.getStorage().set(LOGIN_USER_KEY, loginUserInfo);
        return loginUserInfo;
    }

    /**
     * 获取用户基于token
     */
    public static LoginUserInfo getLoginUser(String token) {
        SaSession session = StpUtil.getTokenSessionByToken(token);
        if (ObjectUtil.isNull(session)) {
            return new LoginUserInfo();
        }
        return (LoginUserInfo) session.get(LOGIN_USER_KEY);
    }

    /**
     * 获取用户id
     */
    public static Long getUserId() {
        Long userId;
        try {
            userId = Convert.toLong(SaHolder.getStorage().get(USER_ID_KEY));
            if (ObjectUtil.isNull(userId)) {
                userId = Convert.toLong(StpUtil.getExtra(USER_ID_KEY));
                SaHolder.getStorage().set(USER_ID_KEY, userId);
            }
        } catch (Exception e) {
            return CoreConstant.DEFAULT_ID;
        }
        return userId;
    }

    /**
     * 获取租户ID
     */
    public static String getTenantId() {
        String tenantId;
        try {
            tenantId = (String) SaHolder.getStorage().get(TENANT_ID_KEY);
            if (ObjectUtil.isNull(tenantId)) {
                tenantId = (String) StpUtil.getExtra(TENANT_ID_KEY);
                SaHolder.getStorage().set(TENANT_ID_KEY, tenantId);
            }
        } catch (Exception e) {
            return "";
        }
        return tenantId;
    }

}
